// 工具定义与类型
// 作用：定义 Agent 能 "做什么"—— 每个工具都是一个具体的 "行动能力"（搜索、计算、查时间）。
// 关键设计：
// 继承 @langchain/core/tools 的 Tool 类，符合 LangChain 生态的工具规范，方便后续调用。
// 用 Zod 的 schema 定义工具的输入参数（比如搜索需要 "query"，计算需要 "expression"），确保输入合法。
// _call 方法是工具的 "执行逻辑"（比如搜索返回模拟结果，计算执行安全求值）。
import { Tool } from "@langchain/core/tools";
import { z } from "zod";
import { getWeatherData } from "./weather-api";

// 基础工具接口
export interface BaseTool {
  name: string;
  description: string;
  schema: z.ZodSchema;
  parameterAliases?: Record<string, string>;
  func: (...args: any[]) => Promise<any>;
}

// 搜索工具
export class SearchTool extends Tool {
  name = "search";
  description = "搜索网络信息，输入搜索关键词";
  schema = z.object({ query: z.string().describe("搜索关键词") });
  parameterAliases = {
    keyword: "query",
    search_query: "query"
  };
  async _call(input: { query: string }) {
    // 模拟搜索，实际可接入 Google/Bing API
    return `搜索结果：${input.query} 的相关信息...`;
  }
}

// 计算工具
export class CalculatorTool extends Tool {
  name = "calculator";
  description = "执行数学计算，支持加减乘除和基本函数。参数名必须是 expression，例如：{\"expression\": \"10+20*3\"}";
  // 参数别名映射
  parameterAliases = { equation: "expression" };
  schema = z.object({
    expression: z.string().describe("数学表达式，如 2+3*4 或 10+20*3，支持空格但会被自动移除")
  });
  async _call(input: { expression?: string; equation?: string }) {
    try {
      // 支持 expression 和 equation 两种参数名
      const expr = input.expression || input.equation || "";
      if (!expr) {
        return `计算错误：缺少数学表达式`;
      }
      // 安全计算，避免 eval
      const result = this.safeEval(expr);
      return `计算结果：${result}`;
    } catch (error) {
      return `计算错误：${error}`;
    }
  }

  private safeEval(expr: string): number {
    // 移除所有空格
    const cleanedExpr = expr.replace(/\s+/g, "");
    // 简化的安全计算实现
    const allowed = /^[0-9+\-*/().]+$/;
    if (!allowed.test(cleanedExpr)) {
      throw new Error(`包含非法字符。只允许数字、运算符 +-*/() 和小数点`);
    }
    try {
      return Function(`"use strict"; return (${cleanedExpr})`)();
    } catch (error) {
      throw new Error(`表达式无效：${error}`);
    }
  }
}

// 时间工具
export class TimeTool extends Tool {
  name = "get_time";
  description = "获取当前时间";
  schema = z.object({});

  async _call() {
    const now = new Date();
    console.log(now)

    return `当前时间：${now.toLocaleString('zh-CN')}`;
  }
}

// 查询城市编号工具
export class GeocodingTool extends Tool {
  name = "getGeocode"; // 工具名（必须唯一，供LLM调用）

  description = "通过城市名称查询经纬度。输入参数为城市名（如'北京'）"
  schema = z.object({
    city: z.string().describe("需要查询经纬度的城市名称，如'上海'、'New York'"),
  });

  // 参数别名映射
  parameterAliases = { cityName: "city", location: "city" };

  async _call(input: { city: string }): Promise<string> {
    const { city } = input;

    // 模拟地理编码数据（实际项目中替换为真实API调用）
    const mockGeocodes: Record<string, { latitude: number; longitude: number }> = {
      "北京": { latitude: 39.9042, longitude: 116.4074 },
      "上海": { latitude: 31.2304, longitude: 121.4737 },
      "广州": { latitude: 23.1291, longitude: 113.2644 },
      "New York": { latitude: 40.7128, longitude: -74.0060 },
    };

    // 查找模拟数据，未找到则返回提示
    const geocode = mockGeocodes[city];
    if (geocode) {
      return JSON.stringify(geocode);
    } else {
      return `未找到城市"${city}"的经纬度，请检查城市名称是否正确。`;
    }
  }
}

// 查询天气工具
export class WeatherTool extends Tool {
  // 工具名：和你之前的天气工具一致，方便模型识别
  name = "getCurrentWeather";
  // 工具描述：清晰说明"能做什么+需要什么参数"，模型靠这个判断是否匹配问题
  // 重要：如果用户问的是城市名（如"北京"），需要先调用 getGeocode 工具获取经纬度，然后再调用此工具
  // 如果用户已经提供了经纬度，直接使用经纬度调用此工具，不需要再调用 getGeocode
  description = "用于获取指定位置的当前天气。需要传入经纬度（latitude 和 longitude）。使用场景：1) 如果用户直接提供了经纬度，直接使用经纬度调用此工具；2) 如果用户问的是城市名（如'北京'），请先调用 getGeocode 工具获取该城市的经纬度，然后再调用此工具。返回的数据包含：湿度(humidity)、天气状况(text)、温度(temp)、风向(windDir)";
  // 参数schema：用Zod定义，确保模型传入正确格式的参数
  schema = z.object({
    latitude: z.union([z.number(), z.string()]).describe("纬度，例如 39.9042（北京）"),
    longitude: z.union([z.number(), z.string()]).describe("经度，例如 116.4074（北京）")
  });
  parameterAliases = { lat: "latitude", lon: "longitude", long: "longitude" };
  // 工具执行逻辑：调用真实的和风天气API
  async _call(input: { latitude: number | string; longitude: number | string }) {
    try {
      // 调用真实的和风天气API
      const weatherData = await getWeatherData(input.latitude, input.longitude);

      // 格式化返回数据，只包含需要的字段
      const result = {
        humidity: weatherData.humidity + '%', // 湿度，添加%符号
        text: weatherData.text,                 // 天气状况文字描述（如"晴"、"多云"）
        temp: weatherData.temp + '°C',         // 温度，添加°C符号
        windDir: weatherData.windDir,           // 风向（如"西南风"）
        windScale: weatherData.windScale,       // 风力等级（额外信息）
        vis: weatherData.vis,                   // 能见度（额外信息）
        updateTime: weatherData.updateTime      // 更新时间
      };

      return JSON.stringify(result, null, 2); // 返回格式化的JSON字符串，方便模型解析
    } catch (error) {
      // 如果API调用失败，返回错误信息
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      return `获取天气数据失败：${errorMessage}。请检查经纬度是否正确，或稍后重试。`;
    }
  }
}
